#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netdb.h>
#include <fcntl.h>
#include <signal.h>
#include "planificador.h"
#include "FuncionesPPD.h"
#include "Prueba-ArchConfig.h"
#include "consola.h"
#include "Socket-Server.h"
#include "Socket-Client.h"
#include "serializable.h"
#include "TModo.h"





//#include "I_O_Disco.h"

void *TconsolaClient ( void *parametro){
	datosConfigPPD * config=(datosConfigPPD *) parametro;
	int32_t sock = CreaConexionclient_UXIT(config->puertoConsola);
	char Cadena2[600];
	int resividos=recv(sock,Cadena2, 512,MSG_CONFIRM);
	printf("bit que llegaron: %i\n",resividos);
	printf("lo que llego: %s\n",Cadena2);
	close(sock);

return NULL;
}


void *TmodoPRUEBAS ( void *parametro){
	struct sockaddr_in direccionRem;
	socklen_t direccionRemSize;
	int32_t socketEntrada = CreaConexionServer_INET ((char *)archPPD->puerto);
	direccionRemSize = sizeof(direccionRem);
	int32_t SockFS = accept(socketEntrada,(struct sockaddr*) &direccionRem, &direccionRemSize);
	if( handshakePPD_FS(SockFS) != 1) {
		printf("error hs Prueba");
		return NULL;
	}
	Message aHandshakeMsg;
	Serializable_t aSerializable;
	aHandshakeMsg.type = msgRead;
	aHandshakeMsg.sectorRequest = 1;
	aHandshakeMsg.contentSize = 0;
	aHandshakeMsg.content = 0;
	Serialize_Message(&aSerializable,aHandshakeMsg);
	sleep(5);
	send(SockFS, aSerializable.Data,aSerializable.Size,MSG_CONFIRM);
	perror("send");
	Serializable_Free(&aSerializable);
	char * revicidosPrueba;
/*	revicidosPrueba = malloc(600);
	recv(SockFS,revicidosPrueba ,600,MSG_CONFIRM);
	aSerializable.Data = revicidosPrueba;
	Deserialize_Message(&aHandshakeMsg, aSerializable);
	Serializable_Free(&aSerializable);
	printf("lo que leyo: %s \n",aHandshakeMsg.content);
*/
	aHandshakeMsg.type = msgRead;
	aHandshakeMsg.sectorRequest = 5;
	Serialize_Message(&aSerializable,aHandshakeMsg);
//	sleep(5);
	send(SockFS, aSerializable.Data,aSerializable.Size,MSG_CONFIRM);
	perror("send");
	Serializable_Free(&aSerializable);
	revicidosPrueba = malloc(600);
	recv(SockFS,revicidosPrueba ,600,MSG_CONFIRM);
	aSerializable.Data = revicidosPrueba;
	Deserialize_Message(&aHandshakeMsg, aSerializable);
//	Serializable_Free(&aSerializable);
	printf("lo que leyo: %s para sector : %i \n",aHandshakeMsg.content, aHandshakeMsg.sectorRequest);

	recv(SockFS,revicidosPrueba ,600,MSG_CONFIRM);
	aSerializable.Data = revicidosPrueba;
	Deserialize_Message(&aHandshakeMsg, aSerializable);
	Serializable_Free(&aSerializable);
	printf("lo que leyo: %s para sector : %i \n",aHandshakeMsg.content, aHandshakeMsg.sectorRequest);


	sleep(10);

//	free(revicidosPrueba);
	return NULL;
}

uint32_t SizeOfDisk;

void finProcess(){
//	printf("Paso por interupcion \n");
	if (msync(punteroMmap, SizeOfDisk, MS_SYNC) != 0)
		perror("msync");
	//munmap(punteroMmap,SizeOfDisk);
	free(CHStot);
	free(CHSActual);
	exit(0);
}


int main(void){

	archPPD= configPPD();
	CHStot = pasajeCHS((char*)archPPD->cHS);
	sem_init(&semContadorL,0,0);
	 subiendo = 1 ;
	 sem_Lista.__align = 0;			//debe arrancar en 1
	 semContador_Lista.__align= 1;
	 Lista= NULL;
	 ListaRev = NULL;
	 Tracer=0;
	 LogFileName = "logPPD.txt";

//	 timeEntreSector=0;
	 double aux= (1 / (atoi((char*)archPPD->rPM) * CHStot->Sector));
	timeEntreSector=(int32_t)aux  * 60 * 1000;

	CHSActual= malloc(sizeof(t_CHS));
	CHSActual->Cilindro=0;
	CHSActual->Hear=1;
	CHSActual->Sector=0;


	int32_t filename= open((char*)archPPD->identificadorDisco , O_RDWR);
	struct stat st;


	if (filename == -1){
		printf("Error en Apertura de Archivo %s \n",(char*)archPPD->identificadorDisco);
		return 1;
	}
	else{
		fstat(filename, &st);
		SizeOfDisk = st.st_size;

		punteroMmap = mmap(NULL,SizeOfDisk,PROT_READ | PROT_WRITE,MAP_SHARED,filename, 0);
		if (punteroMmap == MAP_FAILED){
			 printf("Error en mapeo");
			 close(filename);
			 return 1;
		 }
		 else{
		 	posix_madvise(punteroMmap,512,POSIX_MADV_SEQUENTIAL);
		 	signal(SIGINT,finProcess);
		 }
	}
//----------------------------------//
	   pid_t pID = fork();
	   if (pID == 0)                // child
	    {
	       // Code only executed by child process
		   char *arg[ ]= { (char*)archPPD->puertoConsola ,(char *)0};
	   	   execv((char*) archPPD->puertoConsola, arg );
		    int32_t sock = CreaConexionclient_UXIT(archPPD->puertoConsola);
		    char line[300 + 1];
		    char lineReciv[300 + 1];
		    char comando[301 ];
		    if(sock == -1){
		    	printf("ERROR CHILD, KILL");
		    	exit(1);
		    }
		    fgets(line, 301, stdin);
		    strncpy(comando, line, strpos(line, '\n'));
		   	while (strcmp(line, "exit") != 0){
		   		send(sock,line,strlen(line),MSG_CONFIRM);
		   		recv(sock,lineReciv, strlen(lineReciv),MSG_CONFIRM);
		   		memset(line,0,301);
		    	fgets(line, 301, stdin);
		    	strncpy(comando, line, strpos(line, '\n'));
		    }

		   	close(sock);
		   return 0;
	    }
	   else if (pID < 0)
	    {
		   printf("ERROR en FORK");
		   exit(1);
	        // Throw exception
	    }
	  else  						 // parent
	  	  {
     // Code only executed by parent process

		pthread_t tidConsolaServer;
		pthread_attr_t attrConsola;
		pthread_attr_init(&attrConsola);
		pthread_create (&tidConsolaServer, &attrConsola,  TconsolaServer , (void *) archPPD);

		//creacion de Thread modo inicio//

		pthread_t tidModo;
		pthread_attr_t attrModo;
		pthread_attr_init(&attrModo);
		pthread_create (&tidModo, &attrModo,  Tmodoinicio , (void *) archPPD);

/*
		pthread_t tidPRUEBAS;
		pthread_attr_t attrPRUEBAS;
		pthread_attr_init(&attrPRUEBAS);
		pthread_create (&tidPRUEBAS, &attrPRUEBAS,  TmodoPRUEBAS , (void *) archPPD);
*/

		planifica((void *) archPPD);

    }
  // Code executed by both parent and child.
	munmap(punteroMmap,SizeOfDisk);
	free(CHStot);
	free(CHSActual);
	return 1;
}





